package cn.gpic.message;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import cn.gpic.message.entity.MapInitializer;

/**
 * 企业微信消息推送服务类
 * @author JeffreyWang
 *
 */
public class WeChatMessageService {
	private Logger log = LoggerFactory.getLogger(WeChatMessageService.class);
	
	/**
	 * 构造函数
	 * @param corpId 企业ID
	 * @param corpSecret 应用的凭证密钥
	 */
	public WeChatMessageService(String corpId, String corpSecret) {
		this.corpId = corpId;
		this.corpSecret = corpSecret;
	}
	private String corpId;
	private String corpSecret;

	//企业微信消息请求地址
    private static final String URL_PATTERN = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=";
    
    /**
     * 发送企业微信消息
     * @param msgtype 消息类型，具体参见cn.gpic.message.common.MessageType
     * @param touser 成员列表，成员ID列表（消息接收者，多个接收者用‘|’分隔，最多支持1000个）。特殊情况：指定为@all，则向关注该企业应用的全部成员发送
     * @param toparty 部门ID列表，多个接收者用‘|’分隔，最多支持100个。当touser为@all时忽略本参数
     * @param totag 标签ID列表，多个接收者用‘|’分隔，最多支持100个。当touser为@all时忽略本参数
     * @param initializer
     * @param agentId  企业应用的id
     */
    public void sendMessage(String msgtype, String touser, String toparty, String totag, 
    							MapInitializer<String, String> initializer, String agentId) {
    	

    	 
        log.info("企业应用{}发送{}消息给{}", agentId, msgtype, touser);
        //准备构造JSON
        JSONObject firstjsonObject = new JSONObject();
        JSONObject msgtypejsonObject = new JSONObject();
        //图文类JSON构造
        JSONArray jsonArray = new JSONArray();
        JSONObject secandjsonObject = new JSONObject();
        //填充消息参数
        Map<String, String> map = new HashMap<>();
        //填充图文类多节点参数
        List<Map<String, String>> list = new ArrayList<>();
        //构造通用消息参数JSON
        firstjsonObject.put("touser", touser);
        firstjsonObject.put("toparty", toparty);
        firstjsonObject.put("totag", totag);
        firstjsonObject.put("msgtype", msgtype);
        firstjsonObject.put("agentid", agentId);
        switch (msgtype) {
            case "text":
                initializer.init(map);
                //构造消息主体JSON
                for (String paramName : map.keySet()) {
                    msgtypejsonObject.put(paramName, map.get(paramName));
                }
                firstjsonObject.put("text", msgtypejsonObject);
                firstjsonObject.put("safe", 0);
                break;
            case "image":
                initializer.init(map);
                //构造消息主体JSON
                for (String paramName : map.keySet()) {
                    msgtypejsonObject.put(paramName, map.get(paramName));
                }
                firstjsonObject.put("image", msgtypejsonObject);
                firstjsonObject.put("safe", 0);
                break;
            case "voice":
                initializer.init(map);
                //构造消息主体JSON
                for (String paramName : map.keySet()) {
                    msgtypejsonObject.put(paramName, map.get(paramName));
                }
                firstjsonObject.put("voice", msgtypejsonObject);
                break;
            case "video":
                initializer.init(map);
                //构造消息主体JSON
                for (String paramName : map.keySet()) {
                    msgtypejsonObject.put(paramName, map.get(paramName));
                }
                firstjsonObject.put("video", msgtypejsonObject);
                firstjsonObject.put("safe", 0);
                break;
            case "file":
                initializer.init(map);
                //构造消息主体JSON
                for (String paramName : map.keySet()) {
                    msgtypejsonObject.put(paramName, map.get(paramName));
                }
                firstjsonObject.put("file", msgtypejsonObject);
                firstjsonObject.put("safe", 0);
                break;
            case "textcard":
                initializer.init(map);
                //构造消息主体JSON
                for (String paramName : map.keySet()) {
                    msgtypejsonObject.put(paramName, map.get(paramName));
                }
                firstjsonObject.put("textcard", msgtypejsonObject);
                break;
            case "news":
                initializer.initListMap(list);
                //构造消息主体JSON
                for (int i = 0; i <= list.size() - 1; i++) {
                    secandjsonObject = new JSONObject();
                    for (String paramName : list.get(i).keySet()) {
                        secandjsonObject.put(paramName, list.get(i).get(paramName));
                    }
                    jsonArray.add(secandjsonObject);
                }
                log.info(jsonArray.toJSONString());
                msgtypejsonObject.put("articles", jsonArray);
                firstjsonObject.put("news", msgtypejsonObject);
                break;
            case "mpnews":
                initializer.initListMap(list);
                //构造消息主体JSON
                for (int i = 0; i <= list.size() - 1; i++) {
                    secandjsonObject = new JSONObject();
                    for (String paramName : list.get(i).keySet()) {
                        secandjsonObject.put(paramName, list.get(i).get(paramName));
                    }
                    jsonArray.add(secandjsonObject);
                }
                log.info(jsonArray.toJSONString());
                msgtypejsonObject.put("articles", jsonArray);
                firstjsonObject.put("mpnews", msgtypejsonObject);
                break;
            case "markdown":
                initializer.init(map);
                //构造消息主体JSON
                for (String paramName : map.keySet()) {
                    msgtypejsonObject.put(paramName, map.get(paramName));
                }
                firstjsonObject.put("markdown", msgtypejsonObject);
                break;
            case "miniprogram_notice":
                initializer.init(map);
                initializer.initListMap(list);
                //构造消息主体JSON
                for (String paramName : map.keySet()) {
                    msgtypejsonObject.put(paramName, map.get(paramName));
                }
                //构造消息节点JSON
                for (int i = 0; i <= list.size() - 1; i++) {
                    secandjsonObject = new JSONObject();
                    for (String paramName : list.get(i).keySet()) {
                        secandjsonObject.put(paramName, list.get(i).get(paramName));
                    }
                    jsonArray.add(secandjsonObject);
                }
                log.info(jsonArray.toJSONString());
                msgtypejsonObject.put("content_item", jsonArray);
                firstjsonObject.put("miniprogram_notice", msgtypejsonObject);
                break;
            case "taskcard":
                initializer.init(map);
                initializer.initListMap(list);
                //构造消息主体JSON
                for (String paramName : map.keySet()) {
                    msgtypejsonObject.put(paramName, map.get(paramName));
                }
                //构造消息节点JSON
                for (int i = 0; i <= list.size() - 1; i++) {
                    secandjsonObject = new JSONObject();
                    for (String paramName : list.get(i).keySet()) {
                        secandjsonObject.put(paramName, list.get(i).get(paramName));
                    }
                    jsonArray.add(secandjsonObject);
                }
                log.info(jsonArray.toJSONString());
                msgtypejsonObject.put("btn", jsonArray);
                firstjsonObject.put("taskcard", msgtypejsonObject);
                break;
        }
        sendTo(agentId, firstjsonObject.toJSONString());
    }
 
    /**
     * 推送消息
     * @param agentId
     * @param tempdata
     */
    private void sendTo(String agentId, String messageData) {
        String accessToken = getAccessToken(this.corpId, this.corpSecret);
        String url = URL_PATTERN + accessToken;
        JSONObject jsonObject = post(url, messageData);
        if (!StringUtils.isEmpty(jsonObject.toJSONString()) && jsonObject.getInteger("errcode") == 0) {
            log.info("消息推送成功");
        } else {
            log.info("消息推送失败 原因：{}", jsonObject.toJSONString());
        }
    }
 
    
    public static String getAccessToken(String corpId, String corpSecret) {
    		String result = "";
    		StringBuilder urlBuilder = new StringBuilder();
    		urlBuilder.append("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=").append(corpId)
    				.append("&corpsecret=").append(corpSecret);
    		try {
    			URL url = new URL(urlBuilder.toString());
    			URLConnection URLconnection = url.openConnection();
    			HttpURLConnection httpConnection = (HttpURLConnection) URLconnection;
    			httpConnection.setRequestMethod("GET");
    			httpConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
    			httpConnection.setDoInput(true);
    			InputStream is = httpConnection.getInputStream();
    			InputStreamReader isr = new InputStreamReader(is);
    			BufferedReader br = new BufferedReader(isr);
    			String tempLine = "";

    			String text;
    			for (text = ""; (tempLine = br.readLine()) != null; text = text.concat(tempLine)) {
    			}

    			JSONObject result1 = JSONArray.parseObject(text);
    			result = result1.getString("access_token");
    			return result;
    		} catch (MalformedURLException var11) {
    			var11.printStackTrace();
    			return result;
    		} catch (IOException var12) {
    			var12.printStackTrace();
    			return result;
    		}
    }
    
    
    /**
     * POST请求的RAW参数传递
     *
     * @param url
     * @param body
     * @return
     */
    private static JSONObject post(String url, String body) {
        JSONObject jsonObject = null;
        CloseableHttpClient httpClient = null;
        HttpPost httpPost = null;
        try {
            httpClient = HttpClients.createDefault();
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(20000).setConnectTimeout(20000).build();
            httpPost = new HttpPost(url);
            httpPost.setConfig(requestConfig);
            httpPost.setEntity(new StringEntity(body, "utf-8"));
            CloseableHttpResponse response = httpClient.execute(httpPost);
            HttpEntity httpEntity = response.getEntity();
            jsonObject = JSONObject.parseObject(EntityUtils.toString(httpEntity, "utf-8"));
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } 
        return jsonObject;
    }
    
}
